home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / util / Date.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  48.9 KB  |  1,174 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)Date.java    1.60 98/09/23
  3.  *
  4.  * Copyright 1994-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.util;
  16.  
  17. import java.util.Calendar;
  18. import java.util.GregorianCalendar;
  19. import java.util.TimeZone;
  20. import java.text.DateFormat;
  21. import java.text.SimpleDateFormat;
  22. import java.io.IOException;
  23. import java.io.ObjectOutputStream;
  24. import java.io.ObjectInputStream;
  25. import java.lang.ref.SoftReference;
  26.  
  27. /**
  28.  * The class <code>Date</code> represents a specific instant
  29.  * in time, with millisecond precision.
  30.  * <p>
  31.  * Prior to JDK 1.1, the class <code>Date</code> had two additional
  32.  * functions.  It allowed the interpretation of dates as year, month, day, hour,
  33.  * minute, and second values.  It also allowed the formatting and parsing
  34.  * of date strings.  Unfortunately, the API for these functions was not
  35.  * amenable to internationalization.  As of JDK 1.1, the
  36.  * <code>Calendar</code> class should be used to convert between dates and time
  37.  * fields and the <code>DateFormat</code> class should be used to format and
  38.  * parse date strings.
  39.  * The corresponding methods in <code>Date</code> are deprecated.
  40.  * <p>
  41.  * Although the <code>Date</code> class is intended to reflect 
  42.  * coordinated universal time (UTC), it may not do so exactly, 
  43.  * depending on the host environment of the Java Virtual Machine. 
  44.  * Nearly all modern operating systems assume that 1 day =
  45.  * 24 × 60 × 60 = 86400 seconds 
  46.  * in all cases. In UTC, however, about once every year or two there 
  47.  * is an extra second, called a "leap second." The leap 
  48.  * second is always added as the last second of the day, and always 
  49.  * on December 31 or June 30. For example, the last minute of the 
  50.  * year 1995 was 61 seconds long, thanks to an added leap second. 
  51.  * Most computer clocks are not accurate enough to be able to reflect 
  52.  * the leap-second distinction. 
  53.  * <p>
  54.  * Some computer standards are defined in terms of Greenwich mean 
  55.  * time (GMT), which is equivalent to universal time (UT).  GMT is 
  56.  * the "civil" name for the standard; UT is the 
  57.  * "scientific" name for the same standard. The 
  58.  * distinction between UTC and UT is that UTC is based on an atomic 
  59.  * clock and UT is based on astronomical observations, which for all 
  60.  * practical purposes is an invisibly fine hair to split. Because the 
  61.  * earth's rotation is not uniform (it slows down and speeds up 
  62.  * in complicated ways), UT does not always flow uniformly. Leap 
  63.  * seconds are introduced as needed into UTC so as to keep UTC within 
  64.  * 0.9 seconds of UT1, which is a version of UT with certain 
  65.  * corrections applied. There are other time and date systems as 
  66.  * well; for example, the time scale used by the satellite-based 
  67.  * global positioning system (GPS) is synchronized to UTC but is 
  68.  * <i>not</i> adjusted for leap seconds. An interesting source of 
  69.  * further information is the U.S. Naval Observatory, particularly 
  70.  * the Directorate of Time at:
  71.  * <blockquote><pre>
  72.  *     http://tycho.usno.navy.mil
  73.  * </pre></blockquote>
  74.  * <p>
  75.  * and their definitions of "Systems of Time" at:
  76.  * <blockquote><pre>
  77.  *     http://tycho.usno.navy.mil/systime.html
  78.  * </pre></blockquote>
  79.  * <p>
  80.  * In all methods of class <code>Date</code> that accept or return 
  81.  * year, month, date, hours, minutes, and seconds values, the 
  82.  * following representations are used: 
  83.  * <ul>
  84.  * <li>A year <i>y</i> is represented by the integer 
  85.  *     <i>y</i> <code>- 1900</code>. 
  86.  * <li>A month is represented by an integer form 0 to 11; 0 is January, 
  87.  *     1 is February, and so forth; thus 11 is December. 
  88.  * <li>A date (day of month) is represented by an integer from 1 to 31 
  89.  *     in the usual manner. 
  90.  * <li>An hour is represented by an integer from 0 to 23. Thus, the hour 
  91.  *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1 
  92.  *     p.m. is hour 12. 
  93.  * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
  94.  * <li>A second is represented by an integer from 0 to 61; the values 60 and 
  95.  *     61 occur only for leap seconds and even then only in Java 
  96.  *     implementations that actually track leap seconds correctly. Because 
  97.  *     of the manner in which leap seconds are currently introduced, it is 
  98.  *     extremely unlikely that two leap seconds will occur in the same 
  99.  *     minute, but this specification follows the date and time conventions 
  100.  *     for ISO C.
  101.  * </ul>
  102.  * <p>
  103.  * In all cases, arguments given to methods for these purposes need 
  104.  * not fall within the indicated ranges; for example, a date may be 
  105.  * specified as January 32 and is interpreted as meaning February 1.
  106.  *
  107.  * @author  James Gosling
  108.  * @author  Arthur van Hoff
  109.  * @author  Alan Liu
  110.  * @version 1.60 09/23/98
  111.  * @see     java.text.DateFormat
  112.  * @see     java.util.Calendar
  113.  * @see     java.util.TimeZone
  114.  * @since   JDK1.0
  115.  */
  116. public class Date implements java.io.Serializable, Cloneable, Comparable {
  117.     /* DEFAULT ZONE SYNCHRONIZATION: Part of the usage model of Date
  118.      * is that a Date object behaves like a Calendar object whose zone
  119.      * is the current default TimeZone.  As a result, we must be
  120.      * careful about keeping this phantom calendar in sync with the
  121.      * default TimeZone.  There are three class and instance variables
  122.      * to watch out for to achieve this.  (1)staticCal. Whenever this
  123.      * object is used, it must be reset to the default zone. This is a
  124.      * cheap operation which can be done directly (just a reference
  125.      * assignment), so we just do it every time. (2)simpleFormatter.
  126.      * Likewise, the DateFormat object we use to implement toString()
  127.      * must be reset to the current default zone before use.  Again,
  128.      * this is a cheap reference assignment. (3)cal. This is a little
  129.      * more tricky.  Unlike the other cached static objects, cal has
  130.      * state, and we don't want to monkey with it willy-nilly.  The
  131.      * correct procedure is to change the zone in a way that doesn't
  132.      * alter the time of this object.  This means getting the millis
  133.      * (forcing a fields->time conversion), setting the zone, and then
  134.      * restoring the millis.  The zone must be set before restoring
  135.      * the millis.  Since this is an expensive operation, we only do
  136.      * this when we have to. - liu 1.2b4 */
  137.  
  138.     /* If cal is null, then fastTime indicates the time in millis.
  139.      * Otherwise, fastTime is ignored, and cal indicates the time.
  140.      * The cal object is only created if a setXxx call is made to
  141.      * set a field.  For other operations, staticCal is used instead.
  142.      */
  143.     private transient Calendar cal;
  144.     private transient long fastTime;
  145.  
  146.     private static Calendar staticCal = null;
  147.     private static Calendar utcCal = null;
  148.     private static int defaultCenturyStart = 0;
  149.  
  150.     /* use serialVersionUID from modified java.util.Date for
  151.      * interoperability with JDK1.1. The Date was modified to write
  152.      * and read only the UTC time.
  153.      */
  154.     private static final long serialVersionUID = 7523967970034938905L;
  155.  
  156.     /**
  157.      * Caches for the DateFormatters used by various toString methods.
  158.      */
  159.     private static SoftReference simpleFormatter = null;
  160.     private static SoftReference gmtFormatter = null;
  161.     
  162.     /**
  163.      * Allocates a <code>Date</code> object and initializes it so that 
  164.      * it represents the time at which it was allocated, measured to the 
  165.      * nearest millisecond. 
  166.      *
  167.      * @see     java.lang.System#currentTimeMillis()
  168.      */
  169.     public Date() {
  170.         this(System.currentTimeMillis());
  171.     }
  172.  
  173.     /**
  174.      * Allocates a <code>Date</code> object and initializes it to 
  175.      * represent the specified number of milliseconds since the 
  176.      * standard base time known as "the epoch", namely January 1, 
  177.      * 1970, 00:00:00 GMT. 
  178.      *
  179.      * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
  180.      * @see     java.lang.System#currentTimeMillis()
  181.      */
  182.     public Date(long date) {
  183.         cal = null;
  184.         fastTime = date;
  185.     }
  186.  
  187.     /**
  188.      * Allocates a <code>Date</code> object and initializes it so that 
  189.      * it represents midnight, local time, at the beginning of the day 
  190.      * specified by the <code>year</code>, <code>month</code>, and 
  191.      * <code>date</code> arguments. 
  192.      *
  193.      * @param   year    the year minus 1900.
  194.      * @param   month   the month between 0-11.
  195.      * @param   date    the day of the month between 1-31.
  196.      * @see     java.util.Calendar
  197.      * @deprecated As of JDK version 1.1,
  198.      * replaced by <code>Calendar.set(year + 1900, month, date)</code>
  199.      * or <code>GregorianCalendar(year + 1900, month, date)</code>.
  200.      */
  201.     public Date(int year, int month, int date) {
  202.         this(year, month, date, 0, 0, 0);
  203.     }
  204.  
  205.     /**
  206.      * Allocates a <code>Date</code> object and initializes it so that 
  207.      * it represents the instant at the start of the minute specified by 
  208.      * the <code>year</code>, <code>month</code>, <code>date</code>, 
  209.      * <code>hrs</code>, and <code>min</code> arguments, in the local 
  210.      * time zone. 
  211.      *
  212.      * @param   year    the year minus 1900.
  213.      * @param   month   the month between 0-11.
  214.      * @param   date    the day of the month between 1-31.
  215.      * @param   hrs     the hours between 0-23.
  216.      * @param   min     the minutes between 0-59.
  217.      * @see     java.util.Calendar
  218.      * @deprecated As of JDK version 1.1,
  219.      * replaced by <code>Calendar.set(year + 1900, month, date,
  220.      * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
  221.      * month, date, hrs, min)</code>.
  222.      */
  223.     public Date(int year, int month, int date, int hrs, int min) {
  224.         this(year, month, date, hrs, min, 0);
  225.     }
  226.  
  227.     /**
  228.      * Allocates a <code>Date</code> object and initializes it so that 
  229.      * it represents the instant at the start of the second specified 
  230.      * by the <code>year</code>, <code>month</code>, <code>date</code>, 
  231.      * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments, 
  232.      * in the local time zone. 
  233.      *
  234.      * @param   year    the year minus 1900.
  235.      * @param   month   the month between 0-11.
  236.      * @param   date    the day of the month between 1-31.
  237.      * @param   hrs     the hours between 0-23.
  238.      * @param   min     the minutes between 0-59.
  239.      * @param   sec     the seconds between 0-59.
  240.      * @see     java.util.Calendar
  241.      * @deprecated As of JDK version 1.1,
  242.      * replaced by <code>Calendar.set(year + 1900, month, date,
  243.      * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
  244.      * month, date, hrs, min, sec)</code>.
  245.      */
  246.     public Date(int year, int month, int date, int hrs, int min, int sec) {
  247.         cal = null;
  248.         if (staticCal == null)
  249.             makeStaticCalendars();
  250.         synchronized (staticCal) {
  251.             staticCal.setTimeZone(TimeZone.getDefault());
  252.             staticCal.clear();
  253.             staticCal.set(year + 1900, month, date, hrs, min, sec);
  254.             fastTime = staticCal.getTimeInMillis();
  255.         }
  256.     }
  257.  
  258.     /**
  259.      * Allocates a <code>Date</code> object and initializes it so that 
  260.      * it represents the date and time indicated by the string 
  261.      * <code>s</code>, which is interpreted as if by the 
  262.      * {@link Date#parse} method. 
  263.      *
  264.      * @param   s   a string representation of the date.
  265.      * @see     java.text.DateFormat
  266.      * @see     java.util.Date#parse(java.lang.String)
  267.      * @deprecated As of JDK version 1.1,
  268.      * replaced by <code>DateFormat.parse(String s)</code>.
  269.      */
  270.     public Date(String s) {
  271.         this(parse(s));
  272.     }
  273.  
  274.     /**
  275.      * Return a copy of this object.
  276.      */
  277.     public Object clone() {
  278.         Date d = null;
  279.         try {
  280.             d = (Date)super.clone();
  281.             if (d.cal != null) d.cal = (Calendar)d.cal.clone();
  282.         } catch (CloneNotSupportedException e) {} // Won't happen
  283.         return d;
  284.     }
  285.     
  286.     /**
  287.      * Determines the date and time based on the arguments. The 
  288.      * arguments are interpreted as a year, month, day of the month, 
  289.      * hour of the day, minute within the hour, and second within the 
  290.      * minute, exactly as for the <tt>Date</tt> constructor with six 
  291.      * arguments, except that the arguments are interpreted relative 
  292.      * to UTC rather than to the local time zone. The time indecated is 
  293.      * returned represented as the distance, measured in milliseconds, 
  294.      * of that time from the epoch (00:00:00 GMT on January 1, 1970).
  295.      *
  296.      * @param   year    the year minus 1900.
  297.      * @param   month   the month between 0-11.
  298.      * @param   date    the day of the month between 1-31.
  299.      * @param   hrs     the hours between 0-23.
  300.      * @param   min     the minutes between 0-59.
  301.      * @param   sec     the seconds between 0-59.
  302.      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
  303.      *          the date and time specified by the arguments. 
  304.      * @see     java.util.Calendar
  305.      * @deprecated As of JDK version 1.1,
  306.      * replaced by <code>Calendar.set(year + 1900, month, date,
  307.      * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
  308.      * month, date, hrs, min, sec)</code>, using a UTC
  309.      * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
  310.      */
  311.     public static long UTC(int year, int month, int date,
  312.                            int hrs, int min, int sec) {
  313.         if (utcCal == null)
  314.             makeStaticCalendars();
  315.         synchronized (utcCal) {
  316.             utcCal.clear();
  317.             utcCal.set(year + 1900, month, date, hrs, min, sec);
  318.             return utcCal.getTimeInMillis();
  319.         }
  320.     }
  321.  
  322.     /**
  323.      * ATtempts to interpret the string <tt>s</tt> as a representation 
  324.      * of a date and time. If the attempt is successful, the time 
  325.      * indicated is returned represented as teh distance, measured in 
  326.      * milliseconds, of that time from the epoch (00:00:00 GMT on 
  327.      * January 1, 1970). If the attempt fails, an 
  328.      * <tt>IllegalArgumentException</tt> is thrown.
  329.      * <p>
  330.      * It accepts many syntaxes; in particular, it recognizes the IETF 
  331.      * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also 
  332.      * understands the continental U.S. time-zone abbreviations, but for 
  333.      * general use, a time-zone offset should be used: "Sat, 12 Aug 1995 
  334.      * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich 
  335.      * meridian). If no time zone is specified, the local time zone is 
  336.      * assumed. GMT and UTC are considered equivalent.
  337.      * <p>
  338.      * The string <tt>s</tt> is processed from left to right, looking for 
  339.      * data of interest. Any material in <tt>s</tt> that is within the 
  340.      * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored. 
  341.      * Parentheses may be nested. Otherwise, the only characters permitted 
  342.      * within <tt>s</tt> are these ASCII characters:
  343.      * <blockquote><pre>
  344.      * abcdefghijklmnopqrstuvwxyz
  345.      * ABCDEFGHIJKLMNOPQRSTUVWXYZ
  346.      * 0123456789,+-:/</pre></blockquote>
  347.      * and whitespace characters.<p>
  348.      * A consecutive sequence of decimal digits is treated as a decimal 
  349.      * number:<ul>
  350.      * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year 
  351.      *     has already been recognized, then the number is a time-zone 
  352.      *     offset. If the number is less than 24, it is an offset measured 
  353.      *     in hours. Otherwise, it is regarded as an offset in minutes, 
  354.      *     expressed in 24-hour time format without punctuation. A 
  355.      *     preceding <tt>-</tt> means a westward offset. Time zone offsets 
  356.      *     are always relative to UTC (Greenwich). Thus, for example, 
  357.      *     <tt>-5</tt> occurring in the string would mean "five hours west 
  358.      *     of Greenwich" and <tt>+0430</tt> would mean "four hours and 
  359.      *     thirty minutes east of Greenwich." It is permitted for the 
  360.      *     string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt> 
  361.      *     redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
  362.      * <li>If a number is greater than 70, it is regarded as a year number. 
  363.      *     It must be followed by a space, comma, slash, or end of string. 
  364.      *     If it is greater than 1900, then 1900 is subtracted from it.
  365.      * <li>If the number is followed by a colon, it is regarded as an hour, 
  366.      *     unless an hour has already been recognized, in which case it is 
  367.      *     regarded as a minute.
  368.      * <li>If the number is followed by a slash, it is regarded as a month 
  369.      *     (it is decreased by 1 to produce a number in the range <tt>0</tt> 
  370.      *     to <tt>11</tt>), unless a month has already been recognized, in 
  371.      *     which case it is regarded as a day of the month.
  372.      * <li>If the number is followed by whitespace, a comma, a hyphen, or 
  373.      *     end of string, then if an hour has been recognized but not a 
  374.      *     minute, it is regarded as a minute; otherwise, if a minute has 
  375.      *     been recognized but not a second, it is regarded as a second; 
  376.      *     otherwise, it is regarded as a day of the month. </ul><p>
  377.      * A consecutive sequence of letters is regarded as a word and treated 
  378.      * as follows:<ul>
  379.      * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but 
  380.      *     the parse fails if an hour has not been recognized or is less 
  381.      *     than <tt>1</tt> or greater than <tt>12</tt>).
  382.      * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt> 
  383.      *     to the hour (but the parse fails if an hour has not been 
  384.      *     recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
  385.      * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY, 
  386.      *     WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring 
  387.      *     case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and 
  388.      *     <tt>Thurs</tt> are ignored.
  389.      * <li>Otherwise, any word that matches any prefix of <tt>JANUARY, 
  390.      *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, 
  391.      *     OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and 
  392.      *     considering them in the order given here, is recognized as
  393.      *     specifying a month and is converted to a number (<tt>0</tt> to 
  394.      *     <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and 
  395.      *     <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which 
  396.      *     is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
  397.      * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring 
  398.      *     case, is treated as referring to UTC. 
  399.      * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>, 
  400.      *     ignoring case, is recognized as referring to the time zone in 
  401.      *     North America that is five, six, seven, or eight hours west of 
  402.      *     Greenwich, respectively. Any word that matches <tt>EDT, CDT, 
  403.      *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as 
  404.      *     referring to the same time zone, respectively, during daylight 
  405.      *     saving time.</ul><p>
  406.      * Once the entire string s has been scanned, it is converted to a time 
  407.      * result in one of two ways. If a time zone or time-zone offset has been 
  408.      * recognized, then the year, month, day of month, hour, minute, and 
  409.      * second are interpreted in UTC and then the time-zone offset is 
  410.      * applied. Otherwise, the year, month, day of month, hour, minute, and 
  411.      * second are interpreted in the local time zone.
  412.      *
  413.      * @param   s   a string to be parsed as a date.
  414.      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
  415.      *          represented by the string argument.
  416.      * @see     java.text.DateFormat
  417.      * @deprecated As of JDK version 1.1,
  418.      * replaced by <code>DateFormat.parse(String s)</code>.
  419.      */
  420.     public static long parse(String s) {
  421.         if (staticCal == null)
  422.             makeStaticCalendars(); // Called only for side-effect of setting defaultCenturyStart
  423.         
  424.         int year = Integer.MIN_VALUE;
  425.         int mon = -1;
  426.         int mday = -1;
  427.         int hour = -1;
  428.         int min = -1;
  429.         int sec = -1;
  430.         int millis = -1;
  431.         int c = -1;
  432.         int i = 0;
  433.         int n = -1;
  434.         int wst = -1;
  435.         int tzoffset = -1;
  436.         int prevc = 0;
  437.     syntax:
  438.         {
  439.             if (s == null)
  440.                 break syntax;
  441.             int limit = s.length();
  442.             while (i < limit) {
  443.                 c = s.charAt(i);
  444.                 i++;
  445.                 if (c <= ' ' || c == ',')
  446.                     continue;
  447.                 if (c == '(') { // skip comments
  448.                     int depth = 1;
  449.                     while (i < limit) {
  450.                         c = s.charAt(i);
  451.                         i++;
  452.                         if (c == '(') depth++;
  453.                         else if (c == ')')
  454.                             if (--depth <= 0)
  455.                                 break;
  456.                     }
  457.                     continue;
  458.                 }
  459.                 if ('0' <= c && c <= '9') {
  460.                     n = c - '0';
  461.                     while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
  462.                         n = n * 10 + c - '0';
  463.                         i++;
  464.                     }
  465.                     if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
  466.                         // timezone offset
  467.                         if (n < 24)
  468.                             n = n * 60; // EG. "GMT-3"
  469.                         else
  470.                             n = n % 100 + n / 100 * 60; // eg "GMT-0430"
  471.                         if (prevc == '+')   // plus means east of GMT
  472.                             n = -n;
  473.                         if (tzoffset != 0 && tzoffset != -1)
  474.                             break syntax;
  475.                         tzoffset = n;
  476.                     } else if (n >= 70)
  477.                         if (year != Integer.MIN_VALUE)
  478.                             break syntax;
  479.                         else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
  480.                             // year = n < 1900 ? n : n - 1900;
  481.                             year = n;
  482.                         else
  483.                             break syntax;
  484.                     else if (c == ':')
  485.                         if (hour < 0)
  486.                             hour = (byte) n;
  487.                         else if (min < 0)
  488.                             min = (byte) n;
  489.                         else
  490.                             break syntax;
  491.                     else if (c == '/')
  492.                         if (mon < 0)
  493.                             mon = (byte) (n - 1);
  494.                         else if (mday < 0)
  495.                             mday = (byte) n;
  496.                         else
  497.                             break syntax;
  498.                     else if (i < limit && c != ',' && c > ' ' && c != '-')
  499.                         break syntax;
  500.                     else if (hour >= 0 && min < 0)
  501.                         min = (byte) n;
  502.                     else if (min >= 0 && sec < 0)
  503.                         sec = (byte) n;
  504.                     else if (mday < 0)
  505.                         mday = (byte) n;
  506.                     // Handle two-digit years < 70 (70-99 handled above).
  507.                     else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
  508.                         year = n;
  509.                     else
  510.                         break syntax;
  511.                     prevc = 0;
  512.                 } else if (c == '/' || c == ':' || c == '+' || c == '-')
  513.                     prevc = c;
  514.                 else {
  515.                     int st = i - 1;
  516.                     while (i < limit) {
  517.                         c = s.charAt(i);
  518.                         if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
  519.                             break;
  520.                         i++;
  521.                     }
  522.                     if (i <= st + 1)
  523.                         break syntax;
  524.                     int k;
  525.                     for (k = wtb.length; --k >= 0;)
  526.                         if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
  527.                             int action = ttb[k];
  528.                             if (action != 0) {
  529.                                 if (action == 1) {  // pm
  530.                                     if (hour > 12 || hour < 1)
  531.                                         break syntax;
  532.                                     else if (hour < 12)
  533.                                         hour += 12;
  534.                                 } else if (action == 14) {  // am
  535.                                     if (hour > 12 || hour < 1)
  536.                                         break syntax;
  537.                                     else if (hour == 12)
  538.                                         hour = 0;
  539.                                 } else if (action <= 13) {  // month!
  540.                                     if (mon < 0)
  541.                                         mon = (byte) (action - 2);
  542.                                     else
  543.                                         break syntax;
  544.                                 } else {
  545.                                     tzoffset = action - 10000;
  546.                                 }
  547.                             }
  548.                             break;
  549.                         }
  550.                     if (k < 0)
  551.                         break syntax;
  552.                     prevc = 0;
  553.                 }
  554.             }
  555.             if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
  556.                 break syntax;
  557.             // Parse 2-digit years within the correct default century.
  558.             if (year < 100) {
  559.                 year += (defaultCenturyStart / 100) * 100;
  560.                 if (year < defaultCenturyStart) year += 100;
  561.             }
  562.             year -= 1900;
  563.             if (sec < 0)
  564.                 sec = 0;
  565.             if (min < 0)
  566.                 min = 0;
  567.             if (hour < 0)
  568.                 hour = 0;
  569.             if (tzoffset == -1) // no time zone specified, have to use local
  570.                 return new Date (year, mon, mday, hour, min, sec).getTime();
  571.             return UTC(year, mon, mday, hour, min, sec) + tzoffset * (60 * 1000);
  572.         }
  573.         // syntax error
  574.         throw new IllegalArgumentException();
  575.     }
  576.     private final static String wtb[] = {
  577.         "am", "pm",
  578.         "monday", "tuesday", "wednesday", "thursday", "friday",
  579.         "saturday", "sunday",
  580.         "january", "february", "march", "april", "may", "june",
  581.         "july", "august", "september", "october", "november", "december",
  582.         "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
  583.         "mst", "mdt", "pst", "pdt"
  584.         // this time zone table needs to be expanded
  585.     };
  586.     private final static int ttb[] = {
  587.         14, 1, 0, 0, 0, 0, 0, 0, 0,
  588.         2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
  589.         10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
  590.         10000 + 5 * 60, 10000 + 4 * 60, // EST/EDT
  591.         10000 + 6 * 60, 10000 + 5 * 60,
  592.         10000 + 7 * 60, 10000 + 6 * 60,
  593.         10000 + 8 * 60, 10000 + 7 * 60
  594.     };
  595.  
  596.     /**
  597.      * Returns a value that is the result of subtracting 1900 from the 
  598.      * year that contains or begins with the instant in time represented 
  599.      * by this <code>Date</code> object, as interpreted in the local 
  600.      * time zone.
  601.      *
  602.      * @return  the year represented by this date, minus 1900.
  603.      * @see     java.util.Calendar
  604.      * @deprecated As of JDK version 1.1,
  605.      * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
  606.      */
  607.     public int getYear() {
  608.         return getField(Calendar.YEAR) - 1900;
  609.     }
  610.  
  611.     /**
  612.      * Sets the year of this <tt>Date</tt> object to be the specified 
  613.      * value plus 1900. This <code>Date</code> object is modified so 
  614.      * that it represents a point in time within the specified year, 
  615.      * with the month, date, hour, minute, and second the same as 
  616.      * before, as interpreted in the local time zone. (Of course, if 
  617.      * the date was February 29, for example, and the year is set to a 
  618.      * non-leap year, then the new date will be treated as if it were 
  619.      * on March 1.)
  620.      *
  621.      * @param   year    the year value.
  622.      * @see     java.util.Calendar
  623.      * @deprecated As of JDK version 1.1,
  624.      * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
  625.      */
  626.     public void setYear(int year) {
  627.         setField(Calendar.YEAR, year + 1900);
  628.     }
  629.  
  630.     /**
  631.      * Returns a number representing the month that contains or begins 
  632.      * with the instant in time represented by this <tt>Date</tt> object. 
  633.      * The value returned is between <code>0</code> and <code>11</code>, 
  634.      * with the value <code>0</code> representing January.
  635.      *
  636.      * @return  the month represented by this date.
  637.      * @see     java.util.Calendar
  638.      * @deprecated As of JDK version 1.1,
  639.      * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
  640.      */
  641.     public int getMonth() {
  642.         return getField(Calendar.MONTH);
  643.     }
  644.  
  645.     /**
  646.      * Sets the month of this date to the specified value. This 
  647.      * <tt>Date</tt> object is modified so that it represents a point 
  648.      * in time within the specified month, with the year, date, hour, 
  649.      * minute, and second the same as before, as interpreted in the 
  650.      * local time zone. If the date was October 31, for example, and 
  651.      * the month is set to June, then the new date will be treated as 
  652.      * if it were on July 1, because June has only 30 days.
  653.      *
  654.      * @param   month   the month value between 0-11.
  655.      * @see     java.util.Calendar
  656.      * @deprecated As of JDK version 1.1,
  657.      * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
  658.      */
  659.     public void setMonth(int month) {
  660.         setField(Calendar.MONTH, month);
  661.     }
  662.  
  663.     /**
  664.      * Returns the day of the month represented by this <tt>Date</tt> object. 
  665.      * The value returned is between <code>1</code> and <code>31</code> 
  666.      * representing the day of the month that contains or begins with the 
  667.      * instant in time represented by this <tt>Date</tt> object, as 
  668.      * interpreted in the local time zone.
  669.      *
  670.      * @return  the day of the month represented by this date.
  671.      * @see     java.util.Calendar
  672.      * @deprecated As of JDK version 1.1,
  673.      * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
  674.      * @deprecated
  675.      */
  676.     public int getDate() {
  677.         return getField(Calendar.DATE);
  678.     }
  679.  
  680.     /**
  681.      * Sets the day of the month of this <tt>Date</tt> object to the 
  682.      * specified value. This <tt>Date</tt> object is modified so that 
  683.      * it represents a point in time within the specified day of the 
  684.      * month, with the year, month, hour, minute, and second the same 
  685.      * as before, as interpreted in the local time zone. If the date 
  686.      * was April 30, for example, and the date is set to 31, then it 
  687.      * will be treated as if it were on May 1, because April has only 
  688.      * 30 days.
  689.      *
  690.      * @param   date   the day of the month value between 1-31.
  691.      * @see     java.util.Calendar
  692.      * @deprecated As of JDK version 1.1,
  693.      * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
  694.      */
  695.     public void setDate(int date) {
  696.         setField(Calendar.DATE, date);
  697.     }
  698.  
  699.     /**
  700.      * Returns the day of the week represented by this date. The 
  701.      * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday, 
  702.      * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> = 
  703.      * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday) 
  704.      * represents the day of the week that contains or begins with 
  705.      * the instant in time represented by this <tt>Date</tt> object, 
  706.      * as interpreted in the local time zone.
  707.      *
  708.      * @return  the day of the week represented by this date.
  709.      * @see     java.util.Calendar
  710.      * @deprecated As of JDK version 1.1,
  711.      * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
  712.      */
  713.     public int getDay() {
  714.         return getField(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY;
  715.     }
  716.  
  717.     /**
  718.      * Returns the hour represented by this <tt>Date</tt> object. The 
  719.      * returned value is a number (<tt>0</tt> through <tt>23</tt>) 
  720.      * representing the hour within the day that contains or begins 
  721.      * with the instant in time represented by this <tt>Date</tt> 
  722.      * object, as interpreted in the local time zone.
  723.      *
  724.      * @return  the hour represented by this date.
  725.      * @see     java.util.Calendar
  726.      * @deprecated As of JDK version 1.1,
  727.      * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
  728.      */
  729.     public int getHours() {
  730.         return getField(Calendar.HOUR_OF_DAY);
  731.     }
  732.  
  733.     /**
  734.      * Sets the hour of this <tt>Date</tt> object to the specified value. 
  735.      * This <tt>Date</tt> object is modified so that it represents a point 
  736.      * in time within the specified hour of the day, with the year, month, 
  737.      * date, minute, and second the same as before, as interpreted in the 
  738.      * local time zone.
  739.      *
  740.      * @param   hours   the hour value.
  741.      * @see     java.util.Calendar
  742.      * @deprecated As of JDK version 1.1,
  743.      * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
  744.      */
  745.     public void setHours(int hours) {
  746.         setField(Calendar.HOUR_OF_DAY, hours);
  747.     }
  748.  
  749.     /**
  750.      * Returns the number of minutes past the hour represented by this date, 
  751.      * as interpreted in the local time zone. 
  752.      * The value returned is between <code>0</code> and <code>59</code>.
  753.      *
  754.      * @return  the number of minutes past the hour represented by this date.
  755.      * @see     java.util.Calendar
  756.      * @deprecated As of JDK version 1.1,
  757.      * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
  758.      */
  759.     public int getMinutes() {
  760.         return getField(Calendar.MINUTE);
  761.     }
  762.  
  763.     /**
  764.      * Sets the minutes of this <tt>Date</tt> object to the specified value. 
  765.      * This <tt>Date</tt> object is modified so that it represents a point 
  766.      * in time within the specified minute of the hour, with the year, month, 
  767.      * date, hour, and second the same as before, as interpreted in the 
  768.      * local time zone.
  769.      *
  770.      * @param   minutes   the value of the minutes.
  771.      * @see     java.util.Calendar
  772.      * @deprecated As of JDK version 1.1,
  773.      * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
  774.      */
  775.     public void setMinutes(int minutes) {
  776.         setField(Calendar.MINUTE, minutes);
  777.     }
  778.  
  779.     /**
  780.      * Returns the number of seconds past the minute represented by this date.
  781.      * The value returned is between <code>0</code> and <code>61</code>. The
  782.      * values <code>60</code> and <code>61</code> can only occur on those 
  783.      * Java Virtual Machines that take leap seconds into account.
  784.      *
  785.      * @return  the number of seconds past the minute represented by this date.
  786.      * @see     java.util.Calendar
  787.      * @deprecated As of JDK version 1.1,
  788.      * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
  789.      */
  790.     public int getSeconds() {
  791.         return getField(Calendar.SECOND);
  792.     }
  793.  
  794.     /**
  795.      * Sets the seconds of this <tt>Date</tt> to the specified value. 
  796.      * This <tt>Date</tt> object is modified so that it represents a 
  797.      * point in time within the specified second of the minute, with 
  798.      * the year, month, date, hour, and minute the same as before, as 
  799.      * interpreted in the local time zone.
  800.      *
  801.      * @param   seconds   the seconds value.
  802.      * @see     java.util.Calendar
  803.      * @deprecated As of JDK version 1.1,
  804.      * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>. 
  805.      */
  806.     public void setSeconds(int seconds) {
  807.         setField(Calendar.SECOND, seconds);
  808.     }
  809.  
  810.     /**
  811.      * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
  812.      * represented by this <tt>Date</tt> object.
  813.      *
  814.      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
  815.      *          represented by this date.
  816.      */
  817.     public long getTime() {
  818.         return (cal == null) ? fastTime : cal.getTimeInMillis();
  819.     }
  820.  
  821.     /**
  822.      * Sets this <tt>Date</tt> object to represent a point in time that is 
  823.      * <tt>time</tt> milliseconds after January 1, 1970 00:00:00 GMT. 
  824.      *
  825.      * @param   time   the number of milliseconds.
  826.      */
  827.     public void setTime(long time) {
  828.         if (cal == null) {
  829.             fastTime = time;
  830.         }
  831.         else {
  832.             cal.setTimeInMillis(time);
  833.         }
  834.     }
  835.  
  836.     /**
  837.      * Tests if this date is before the specified date.
  838.      *
  839.      * @param   when   a date.
  840.      * @return  <code>true</code> if and only if the instant of time 
  841.      *            represented by this <tt>Date</tt> object is strictly 
  842.      *            earlier than the instant represented by <tt>when</tt>;
  843.      *          <code>false</code> otherwise.
  844.      */
  845.     public boolean before(Date when) {
  846.         return getTime() < when.getTime();
  847.     }
  848.  
  849.     /**
  850.      * Tests if this date is after the specified date.
  851.      *
  852.      * @param   when   a date.
  853.      * @return  <code>true</code> if and only if the instant represented 
  854.      *          by this <tt>Date</tt> object is strictly later than the 
  855.      *          instant represented by <tt>when</tt>; 
  856.      *          <code>false</code> otherwise.
  857.      */
  858.     public boolean after(Date when) {
  859.         return getTime() > when.getTime();
  860.     }
  861.  
  862.     /**
  863.      * Compares two dates for equality.
  864.      * The result is <code>true</code> if and only if the argument is 
  865.      * not <code>null</code> and is a <code>Date</code> object that 
  866.      * represents the same point in time, to the millisecond, as this object.
  867.      * <p>
  868.      * Thus, two <code>Date</code> objects are equal if and only if the 
  869.      * <code>getTime</code> method returns the same <code>long</code> 
  870.      * value for both. 
  871.      *
  872.      * @param   obj   the object to compare with.
  873.      * @return  <code>true</code> if the objects are the same;
  874.      *          <code>false</code> otherwise.
  875.      * @see     java.util.Date#getTime()
  876.      */
  877.     public boolean equals(Object obj) {
  878.         return obj != null && obj instanceof Date && getTime() == ((Date) obj).getTime();
  879.     }
  880.  
  881.     /**
  882.      * Compares two Dates for ordering.
  883.      *
  884.      * @param   anotherDate   the <code>Date</code> to be compared.
  885.      * @return  the value <code>0</code> if the argument Date is equal to
  886.      *          this Date; a value less than <code>0</code> if this Date
  887.      *          is before the Date argument; and a value greater than
  888.      *      <code>0</code> if this Date is after the Date argument.
  889.      * @since   JDK1.2
  890.      */
  891.     public int compareTo(Date anotherDate) {
  892.     long thisTime = this.getTime();
  893.     long anotherTime = anotherDate.getTime();
  894.     return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
  895.     }
  896.  
  897.     /**
  898.      * Compares this Date to another Object.  If the Object is a Date,
  899.      * this function behaves like <code>compareTo(Date)</code>.  Otherwise,
  900.      * it throws a <code>ClassCastException</code> (as Dates are comparable
  901.      * only to other Dates).
  902.      *
  903.      * @param   o the <code>Object</code> to be compared.
  904.      * @return  the value <code>0</code> if the argument is a Date
  905.      *      equal to this Date; a value less than <code>0</code> if the
  906.      *      argument is a Date after this Date; and a value greater than
  907.      *      <code>0</code> if the argument is a Date before this Date.
  908.      * @exception ClassCastException if the argument is not a
  909.      *        <code>Date</code>. 
  910.      * @see     java.lang.Comparable
  911.      * @since   JDK1.2
  912.      */
  913.     public int compareTo(Object o) {
  914.     return compareTo((Date)o);
  915.     }
  916.  
  917.     /**
  918.      * Returns a hash code value for this object. The result is the 
  919.      * exclusive OR of the two halves of the primitive <tt>long</tt> 
  920.      * value returned by the {@link Date#getTime} 
  921.      * method. That is, the hash code is the value of the expression:
  922.      * <blockquote><pre>
  923.      * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
  924.      *
  925.      * @return  a hash code value for this object. 
  926.      */
  927.     public int hashCode() {
  928.         long ht = getTime();
  929.         return (int) ht ^ (int) (ht >> 32);
  930.     }
  931.  
  932.     /**
  933.      * Converts this <code>Date</code> object to a <code>String</code> 
  934.      * of the form:
  935.      * <blockquote><pre>
  936.      * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
  937.      * where:<ul>
  938.      * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed, 
  939.      *     Thu, Fri, Sat</tt>).
  940.      * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, 
  941.      *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
  942.      * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through 
  943.      *     <tt>31</tt>), as two decimal digits.
  944.      * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through 
  945.      *     <tt>23</tt>), as two decimal digits.
  946.      * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through 
  947.      *     <tt>59</tt>), as two decimal digits.
  948.      * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through 
  949.      *     <tt>61</tt>, as two decimal digits.
  950.      * <li><tt>zzz</tt> is the time zone (and may reflect daylight savings 
  951.      *     time). Standard time zone abbreviations include those 
  952.      *     recognized by the method <tt>parse</tt>. If time zone 
  953.      *     informationi is not available, then <tt>zzz</tt> is empty - 
  954.      *     that is, it consists of no characters at all.
  955.      * <li><tt>yyyy</tt> is the year, as four decimal digits.
  956.      * </ul>
  957.      *
  958.      * @return  a string representation of this date. 
  959.      * @see     java.util.Date#toLocaleString()
  960.      * @see     java.util.Date#toGMTString()
  961.      */
  962.     public String toString() {
  963.     DateFormat formatter = null;
  964.     if (simpleFormatter != null) {
  965.         formatter = (DateFormat)simpleFormatter.get();
  966.     }
  967.     if (formatter == null) {
  968.         /* No cache yet, or cached formatter GC'd */
  969.         formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy",
  970.                          Locale.US);
  971.         simpleFormatter = new SoftReference(formatter);
  972.     }
  973.         synchronized (formatter) {
  974.             formatter.setTimeZone(TimeZone.getDefault());
  975.             return formatter.format(this);
  976.         }
  977.     }
  978.  
  979.     /**
  980.      * Creates a string representation of this <ttt>Date</tt> object in an 
  981.      * implementation-dependent form. The intent is that the form should 
  982.      * be familiar to the user of the Java application, wherever it may 
  983.      * happen to be running. The intent is comparable to that of the 
  984.      * "<code>%c</code>" format supported by the <code>strftime()</code> 
  985.      * function of ISO C. 
  986.      *
  987.      * @return  a string representation of this date, using the locale
  988.      *          conventions.
  989.      * @see     java.text.DateFormat
  990.      * @see     java.util.Date#toString()
  991.      * @see     java.util.Date#toGMTString()
  992.      * @deprecated As of JDK version 1.1,
  993.      * replaced by <code>DateFormat.format(Date date)</code>.
  994.      */
  995.     public String toLocaleString() {
  996.     DateFormat formatter = DateFormat.getDateTimeInstance();
  997.     return formatter.format(this);
  998.     }
  999.  
  1000.     /**
  1001.      * Creates a string representation of this <tt>Date</tt> object of 
  1002.      * the form:
  1003.      * <blockquote<pre>
  1004.      * d mon yyyy hh:mm:ss GMT</pre></blockquote>
  1005.      * where:<ul>
  1006.      * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>), 
  1007.      *     as one or two decimal digits.
  1008.      * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul, 
  1009.      *     Aug, Sep, Oct, Nov, Dec</tt>).
  1010.      * <li><i>yyyy</i> i sthe year, as four decimal digits.
  1011.      * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>), 
  1012.      *     as two decimal digits.
  1013.      * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through 
  1014.      *     <tt>59</tt>), as two decimal digits.
  1015.      * <li><i>ss</i> is the second within the minute (<tt>00</tt> through 
  1016.      *     <tt>61</tt>), as two decimal digits.
  1017.      * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate 
  1018.      *     Greenwich Mean Time.
  1019.      * </ul><p>
  1020.      * The result does not depend on the local time zone.
  1021.      * 
  1022.      * @return  a string representation of this date, using the Internet GMT
  1023.      *          conventions.
  1024.      * @see     java.text.DateFormat
  1025.      * @see     java.util.Date#toString()
  1026.      * @see     java.util.Date#toLocaleString()
  1027.      * @deprecated As of JDK version 1.1,
  1028.      * replaced by <code>DateFormat.format(Date date)</code>, using a
  1029.      * GMT <code>TimeZone</code>.
  1030.      */
  1031.     public String toGMTString() {
  1032.     DateFormat formatter = null;
  1033.     if (gmtFormatter != null) {
  1034.         formatter = (DateFormat)gmtFormatter.get();
  1035.     }
  1036.     if (formatter == null) {
  1037.         /* No cache yet, or cached formatter GC'd */
  1038.         formatter = new SimpleDateFormat("d MMM yyyy HH:mm:ss 'GMT'", 
  1039.                          Locale.US);
  1040.             formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
  1041.         gmtFormatter = new SoftReference(formatter);
  1042.     }
  1043.         return formatter.format(this);
  1044.     }
  1045.  
  1046.     /**
  1047.      * Returns the offset, measured in minutes, for the local time zone 
  1048.      * relative to UTC that is appropriate for the time represented by 
  1049.      * this <tt>Date</tt> object. 
  1050.      * <p>
  1051.      * For example, in Massachusetts, five time zones west of Greenwich:
  1052.      * <blockquote><pre>
  1053.      * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
  1054.      * because on February 14, 1996, standard time (Eastern Standard Time) 
  1055.      * is in use, which is offset five hours from UTC; but:
  1056.      * <blockquote><pre>
  1057.      * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
  1058.      * because on May 1, 1996, daylight savings time (Eastern Daylight Time) 
  1059.      * is in use, which is offset only four hours from UTC.<p>
  1060.      * This method produces teh same result as if it computed:
  1061.      * <blockquote><pre>
  1062.      * (this.getTime() - UTC(this.getYear(), 
  1063.      *                       this.getMonth(), 
  1064.      *                       this.getDate(),
  1065.      *                       this.getHours(), 
  1066.      *                       this.getMinutes(), 
  1067.      *                       this.getSeconds())) / (60 * 1000)
  1068.      * </pre></blockquote>
  1069.      *
  1070.      * @return  the time-zone offset, in minutes, for the current locale.
  1071.      * @see     java.util.Calendar
  1072.      * @see     java.util.TimeZone
  1073.      * @deprecated As of JDK version 1.1,
  1074.      * replaced by <code>Calendar.get(Calendar.ZONE_OFFSET) +
  1075.      * Calendar.get(Calendar.DST_OFFSET)</code>.
  1076.      */
  1077.     public int getTimezoneOffset() {
  1078.         int offset;
  1079.         if (cal == null) {
  1080.             if (staticCal == null)
  1081.                 makeStaticCalendars();
  1082.             synchronized (staticCal) {
  1083.                 staticCal.setTimeZone(TimeZone.getDefault());
  1084.                 staticCal.setTimeInMillis(getTime());
  1085.                 offset = staticCal.get(Calendar.ZONE_OFFSET) +
  1086.                     staticCal.get(Calendar.DST_OFFSET);
  1087.             }
  1088.         }
  1089.         else {
  1090.             TimeZone defaultZone = TimeZone.getDefault();
  1091.             if (!defaultZone.equals(cal.getTimeZone())) {
  1092.                 long ms = cal.getTimeInMillis();
  1093.                 cal.setTimeZone(TimeZone.getDefault());
  1094.                 cal.setTimeInMillis(ms);
  1095.             }
  1096.             offset = cal.get(Calendar.ZONE_OFFSET) +
  1097.                 cal.get(Calendar.DST_OFFSET);
  1098.         }
  1099.         return -(offset / 1000 / 60);  // convert to minutes
  1100.     }
  1101.  
  1102.     /**
  1103.      * Save the state of this object to a stream (i.e., serialize it).
  1104.      *
  1105.      * @serialData The value returned by <code>getTime()</code>
  1106.      *           is emitted (long).  This represents the offset from
  1107.      *             January 1, 1970, 00:00:00 GMT in milliseconds.
  1108.      */
  1109.     private void writeObject(ObjectOutputStream s)
  1110.          throws IOException
  1111.     {
  1112.         s.writeLong(getTime());
  1113.     }
  1114.  
  1115.     /**
  1116.      * Reconstitute this object from a stream (i.e., deserialize it).
  1117.      */
  1118.     private void readObject(ObjectInputStream s)
  1119.          throws IOException, ClassNotFoundException
  1120.     {
  1121.         fastTime = s.readLong();
  1122.         // we expect to have cal == null here
  1123.     }
  1124.  
  1125.     /**
  1126.      * Return a field for this date by looking it up in a Calendar object.
  1127.      *
  1128.      * @return the field value
  1129.      * @see    java.util.Calendar
  1130.      * @param  field the field to return
  1131.      */
  1132.     private final int getField(int field) {
  1133.         if (cal == null) {
  1134.             if (staticCal == null)
  1135.                 makeStaticCalendars();
  1136.             synchronized (staticCal) {
  1137.                 staticCal.setTimeZone(TimeZone.getDefault());
  1138.                 staticCal.setTimeInMillis(fastTime);
  1139.                 return staticCal.get(field);
  1140.             }
  1141.         }
  1142.         else {
  1143.             TimeZone defaultZone = TimeZone.getDefault();
  1144.             if (!defaultZone.equals(cal.getTimeZone())) {
  1145.                 long ms = cal.getTimeInMillis();
  1146.                 cal.setTimeZone(TimeZone.getDefault());
  1147.                 cal.setTimeInMillis(ms);
  1148.             }
  1149.             return cal.get(field);
  1150.         }
  1151.     }
  1152.  
  1153.     /**
  1154.      * Set a field for this day.
  1155.      *
  1156.      * @param field the field to set
  1157.      * @param value the value to set it to
  1158.      * @see java.util.Calendar
  1159.      */
  1160.     private final void setField(int field, int value) {
  1161.         if (cal == null) {
  1162.             cal = new GregorianCalendar();
  1163.             cal.setTimeInMillis(fastTime);
  1164.         }
  1165.         cal.set(field, value);
  1166.     }
  1167.  
  1168.     private static void makeStaticCalendars() {
  1169.     staticCal = new GregorianCalendar();
  1170.         utcCal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
  1171.         defaultCenturyStart = staticCal.get(Calendar.YEAR) - 80;
  1172.     }
  1173. }
  1174.